package com.apobates.jforum.comments.core;

import com.apobates.jforum.comments.Comments;
import com.apobates.jforum.comments.CommentsRelations;
import com.apobates.jforum.comments.vo.NewsReplyItem;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 百度tieba显示模式
 */
public class TiebaStyleCommentsConverter implements CommentsConverter<NewsReplyItem>{
    //递归遍历的节点深度
    private final int nodeDeep;

    /**
     * 初始化
     *
     * @param nodeDeep 递归遍历的节点深度
     */
    public TiebaStyleCommentsConverter(int nodeDeep) {
        if(nodeDeep<1){
            throw new IllegalStateException("支持的最低深层为1.");
        }
        this.nodeDeep = nodeDeep;
    }

    /**
     * 初始化
     *
     * 递归的深度为3.更深层的评论折叠到最4层
     */
    public TiebaStyleCommentsConverter() {
        this(3);
    }

    @Override
    public List<NewsReplyItem> map(List<Comments> rs, List<CommentsRelations> relations) {
        Set<Integer> hasQuoteEles = relations.stream().map(CommentsRelations::getCommentsId).collect(Collectors.toSet());
        Map<Integer,Comments> cache = rs.stream().collect(Collectors.toMap(Comments::getId, Function.identity()));
        //
        List<NewsReplyItem> data = new ArrayList<>();
        for(Comments c : rs){
            if(hasQuoteEles.contains(c.getId())) { //在引用关系的评论不显示
                continue;
            }
            if(c.isHasQuote()) { //被引用了
                String _seq = c.getId()+"";
                TreeSet<Integer> nodes = getRelationNode(_seq, relations);
                List<NewsReplyItem> replyNodes = getReplyItemList(_seq, cache, nodes, relations);
                data.add(new NewsReplyItem(c, replyNodes));
            }else{ //没被引用.
                data.add(new NewsReplyItem(c));
            }
        }
        return data;
    }

    /**
     * 获取下一级节点树
     *
     * @param nodeSeq 回复序列,例: 2,1
     * @param relations 评论的引用关系
     * @return
     */
    private TreeSet<Integer> getRelationNode(String nodeSeq, List<CommentsRelations> relations){
        TreeSet<Integer> cids = new TreeSet<>();
        for(CommentsRelations cr : relations){
            if(cr.getSequence().equalsIgnoreCase(nodeSeq)){
                cids.add(cr.getCommentsId());
            }
        }
        return cids;
    }

    /**
     * 递归获取下一级函数
     *
     * @param replySeq 回复序列,例: 4,3,2,1
     * @param source 评论的缓存
     * @param relationTree 下一级节点树
     * @param relations 评论的引用关系
     * @return
     */
    private List<NewsReplyItem> getReplyItemList(String replySeq, Map<Integer,Comments> source, TreeSet<Integer> relationTree, List<CommentsRelations> relations){
        List<NewsReplyItem> nodes = new ArrayList<>();
        Iterator<Integer> it = relationTree.iterator();
        while (it.hasNext()) {
            Integer nextCommentId = it.next();
            Comments nodeComment = source.get(nextCommentId);
            //1
            //2,1
            //3,2,1
            if (isDeep(replySeq)){ //到达层级了吗？
                String nextSeq = nextCommentId.toString() + "," + replySeq;
                TreeSet<Integer> getRelationNode = getRelationNode(nextSeq, relations);
                List<NewsReplyItem> replyNodes = getReplyItemList(nextSeq, source, getRelationNode, relations);
                nodes.add(new NewsReplyItem(nodeComment, replyNodes));
            }else{
                String tailSeq = nodeComment.getId() + "," + replySeq;
                List<NewsReplyItem> tailNodes = flodDeepComment(tailSeq, nodeComment.getUser(), source, relations);
                nodes.add(new NewsReplyItem(nodeComment, tailNodes));
            }
        }
        return nodes;
    }

    /**
     * 是否达到了递归的深度
     *
     * @param replySeq 回复序列,例: 4,3,2,1
     * @return true未到了,false到了
     */
    private boolean isDeep(String replySeq){
        return replySeq.chars().filter(ch -> ch == ',').count() < (nodeDeep - 1);
    }


    /**
     * 折叠更深的评论
     *
     * @param replySeq 最后一层的回复序列
     * @param tailUser 最后一层的评论用户
     * @param source 评论的缓存
     * @param relations 评论的引用关系
     * @return
     */
    private List<NewsReplyItem> flodDeepComment(String replySeq, String tailUser, Map<Integer,Comments> source, List<CommentsRelations> relations){
        //全包含=11,10,7,3=12(commentId)-11(seq[0])
        //部分包含=12,11,10,7,3=13(commentId)-12,11(no-seq[0])
        //谁对谁说=谁回复谁
        Map<Integer,NewsReplyItem> dialogue = new TreeMap<>();
        for(CommentsRelations cr : relations){
            if(cr.getSequence().endsWith(replySeq)){
                if(replySeq.equals(cr.getSequence())){ //全包含:回复的是最后一层评论的用户
                    Comments tmp = source.get(cr.getCommentsId());
                    dialogue.put(cr.getCommentsId(), new NewsReplyItem(tmp.getUser()+"回复"+tailUser, tmp));
                }else{
                    //只取第一个元素
                    Integer ratioCommentId = Integer.valueOf(cr.getSequence().split(",")[0]);
                    //被回复的评论
                    Comments ratioComment = source.get(ratioCommentId);
                    //评论
                    Comments author = source.get(cr.getCommentsId());
                    dialogue.put(cr.getCommentsId(), new NewsReplyItem(author.getUser()+"回复"+ratioComment.getUser(), author));
                }
            }
        }

        return new ArrayList<>(dialogue.values());
    }
}
